package cn.xyy.system.service;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import cn.xyy.common.file.FileConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import cn.xyy.system.dao.UserDao;
import cn.xyy.web.AuthUserHolder;
import cn.xyy.common.domain.system.auth.ClientInfo;
import cn.xyy.common.domain.system.auth.Department;
import cn.xyy.common.domain.system.auth.Job;
import cn.xyy.common.domain.system.auth.LoginVO;
import cn.xyy.common.domain.system.auth.ModifyPwdVO;
import cn.xyy.common.domain.system.auth.Permission;
import cn.xyy.common.domain.system.auth.Role;
import cn.xyy.common.domain.system.auth.UserBasicInfoVO;
import cn.xyy.common.domain.system.auth.UserInfo;
import cn.xyy.common.domain.system.auth.UserInfoVO;
import cn.xyy.common.config.ConfigUtil;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.xyy.common.algorithm.DepartmentAlgorithm;
import cn.xyy.common.algorithm.MenuAlgorithm;
import cn.xyy.common.constant.DataScopeType;
import cn.xyy.common.file.FileUtils;
import cn.xyy.common.spring.SpringMVCUtil;
import cn.xyy.common.utils.BeanUtils;
import cn.xyy.common.utils.DateUtils;
import cn.xyy.common.utils.HttpUtils;
import cn.xyy.common.utils.LoggerUtil;
import cn.xyy.common.utils.SecretAESUtils;
import cn.xyy.common.utils.StringUtils;
import cn.xyy.common.exception.SystemException;

/**
 * 用户业务层
 * 
 * @author xyy
 *
 */
@Service
public class AuthService {
	@Autowired
	private UserDao userDao;
	@Autowired
	private RoleService roleService;
	@Autowired
	private PermissionService permissionService;
	@Autowired
	private DepartmentService departmentService;
	@Autowired
	private JobService jobService;

	public void login(LoginVO vo) {
		if (StringUtils.isBlank(vo.getUsername())) {
			throw new SystemException("用户名不能为空");
		}
		if (StringUtils.isBlank(vo.getPassword())) {
			throw new SystemException("密码不能为空");
		}
		// 根据登陆名
		UserInfo user = userDao.selectOne(new UserInfo().setUsername(vo.getUsername()));
		if (user == null) {
			throw new SystemException("无效的用户名或密码");
		}
		String md5password = SaSecureUtil
				.md5(SecretAESUtils.decrypt(ConfigUtil.getAppConfig().getAesKey(), vo.getPassword()));
		if (!user.getPassword().equalsIgnoreCase(md5password)) {
			throw new SystemException("无效的用户名或密码");
		}
		if (UserInfo.user_unable.equals(user.getStatus())) {
			throw new SystemException("该账户已被禁用");
		}

		// 客户端信息
		ClientInfo clientInfo = new ClientInfo();
		clientInfo.setIp(HttpUtils.getIpAddr(SpringMVCUtil.getRequest()));
		clientInfo.setLoginTime(new Date());
		clientInfo.setDevice(vo.getDevice());
		user.setClientInfo(clientInfo);

		// 校验封禁
		StpUtil.checkDisable(user.getUid());
		// 登录
		StpUtil.login(user.getUid(), vo.getDevice());
		// 用户信息存入缓存
		AuthUserHolder.setUserInfo(user);
	}

	public UserInfoVO getUserInfo() {
		// 用户缓存设置了过期时间，为空的时候从数据库更新用户信息到缓存中
		UserInfo user = AuthUserHolder.getUserInfo();
		if (user == null) {
			user = userDao.selectById(StpUtil.getLoginId(), UserInfo.class);
		}
		// 获取当前用户的所属公司
		Department company = DepartmentAlgorithm.findCompany(user.getDeptId(), departmentService.getEnableDeptList());
		if (company == null) {
			throw new SystemException("未查询到当前用户的所属公司");
		}
		// 部门
		Department dept = departmentService.getDept(user.getDeptId());
		if (dept == null) {
			throw new SystemException("未查询到当前用户的部门");
		}
		if (user.getJobId() != null) {
			// 岗位
			Job job = jobService.getJob(user.getJobId());
			if (job != null) {
				user.setJobName(job.getName());
			}
		}
		// 角色
		List<Role> roleList = roleService.getRoleListByUser(user.getUid());
		if (roleList == null || roleList.isEmpty()) {
			throw new SystemException("当前用户未分配角色");
		}
		List<String> roleIdList = roleList.stream().map(Role::getId).collect(Collectors.toList());
		// 角色对应的权限
		List<Permission> permissionList = permissionService
				.getPermissionListByRole(roleIdList.toArray(new String[roleIdList.size()]));

		if (permissionList == null || permissionList.isEmpty()) {
			throw new SystemException("当前用户未分配权限");
		}

		// 找出用户角色拥有最大的数据权限
		Integer datascopeType = roleList.stream()
				.min((e1, e2) -> e1.getDataScopeType().compareTo(e1.getDataScopeType())).get().getDataScopeType();
		user.setDeptName(dept.getName());
		user.setCompanyId(company.getId());
		user.setCompanyName(company.getName());
		user.setRoleList(roleList);
		user.setRoleNameList(roleList.stream().map(Role::getName).collect(Collectors.toList()));
		user.setPermissionCodeList(permissionList.stream().filter(e -> !e.isMenu()).map(Permission::getPermissionCode)
				.collect(Collectors.toList()));
		user.setMenuList(permissionList.stream().filter(e -> e.isMenu()).collect(Collectors.toList()));
		user.setDatascopeType(datascopeType);
		user.setDatascopeList(getDataScopeList(user));
		AuthUserHolder.setUserInfo(user);

		UserInfoVO userInfoVO = new UserInfoVO();
		BeanUtils.copyProperties(user, userInfoVO);
		userInfoVO.setRoleNameList(user.getRoleNameList());
		userInfoVO.setPermissionCodeList(user.getPermissionCodeList());
		userInfoVO.setMenuList(MenuAlgorithm.buildMenu(MenuAlgorithm.tree(user.getMenuList())));
		userInfoVO.setPassword("");

		return userInfoVO;
	}

	/***
	 * 获取角色对应的数据权限
	 *
	 * @param @param  roles
	 * @param @return 设定文件
	 * @return List<Integer> 返回类型
	 *
	 */
	private List<String> getDataScopeList(UserInfo user) {
		List<String> dataScopeList = new ArrayList<String>();
		List<Department> allDeptList = departmentService.getEnableDeptList();
		for (Role role : user.getRoleList()) {
			// 1全部数据权限
			if (DataScopeType.all.equals(role.getDataScopeType())) {
				for (Department dept : allDeptList) {
					dataScopeList.add(dept.getId());
				}
				// 2用户自定义数据权限
			} else if (DataScopeType.customize.equals(role.getDataScopeType())) {
				dataScopeList.addAll(roleService.getDataScopeListByRole(role.getId()));
				// 3本部门及以下数据权限
			} else if (DataScopeType.deptAndBelow.equals(role.getDataScopeType())) {
				List<Department> findSelfAndAllChild = DepartmentAlgorithm.findSelfAndAllChild(user.getDeptId(),
						allDeptList);
				for (Department dept : findSelfAndAllChild) {
					dataScopeList.add(dept.getId());
				}
				// 4本部门数据权限
			} else if (DataScopeType.dept.equals(role.getDataScopeType())) {
				dataScopeList.add(user.getDeptId());
			}
		}
		if (dataScopeList.isEmpty()) {
			// 5仅本人数据权限
			return null;
		}
		// 去重复
		Set<String> ownedSet = new HashSet<String>();
		for (String id : dataScopeList) {
			ownedSet.add(id);
		}
		dataScopeList = new ArrayList<String>(ownedSet);

		return dataScopeList;
	}

	public void modifyPwd(ModifyPwdVO vo) {
		if (StringUtils.isBlank(vo.getPasswordNew()) || StringUtils.isBlank(vo.getPasswordOld())) {
			throw new SystemException("密码不能为空");
		}

		if (!vo.getPasswordNew().equals(vo.getConfirmPassword())) {
			throw new SystemException("两次输入的密码不一致");
		}
		UserInfo user = AuthUserHolder.getUserInfo();

		if (!user.getPassword().equalsIgnoreCase(SaSecureUtil.md5(vo.getPasswordOld()))) {
			throw new SystemException("原密码错误");
		}

		UserInfo userInfo = userDao.selectById(user.getUid(), UserInfo.class);
		if (userInfo == null) {
			throw new SystemException("用户不存在");
		}
		userInfo.setPassword(SaSecureUtil.md5(vo.getPasswordNew()));
		userDao.update(userInfo);
		// 销毁用户，重新登录
		AuthUserHolder.destroyUser();
		StpUtil.logout(user.getUid(), StpUtil.getLoginDevice());

	}

	public void updateBasicInfo(UserBasicInfoVO vo) {

		UserInfo userInfo = userDao.selectById(AuthUserHolder.getUserInfo().getUid(), UserInfo.class);

		BeanUtils.copyProperties(vo, userInfo);
		int result = userDao.update(userInfo);
		if (result < 0) {
			throw new SystemException("修改失败");
		}
		// 更新缓存用户信息
		UserInfo cacheUserInfo = AuthUserHolder.getUserInfo();
		BeanUtils.copyProperties(vo, cacheUserInfo);
		AuthUserHolder.setUserInfo(cacheUserInfo);

	}

	public Map<String, String> updateAvatar(MultipartFile multipartFile) {
		Map<String, String> map = new HashMap<String, String>();
		// 文件大小验证
		try {
			FileUtils.checkSize(FileConstants.avatarMaxSize, multipartFile.getSize());

			// 验证文件上传的格式
			String image = "gif jpg png jpeg";
			String fileType = FileUtils.getExtensionName(multipartFile.getOriginalFilename());
			if (fileType != null && !image.contains(fileType)) {
				throw new SystemException("文件格式错误！, 仅支持 " + image + " 格式");
			}

			String name = FileUtils.getFileNameNoEx(multipartFile.getOriginalFilename());
			String suffix = FileUtils.getExtensionName(multipartFile.getOriginalFilename());
			String fileName = name + "_" + DateUtils.getDateTimeNoBar() + "." + suffix;
			String path = ConfigUtil.getAppConfig().getFile().getPath() + FileConstants.avatar + "/" + fileName;

			File file = FileUtils.upload(multipartFile.getBytes(), path);

			UserInfo user = userDao.selectById(AuthUserHolder.getUserInfo().getUid(), UserInfo.class);
			String oldPath = user.getAvatarPath();
			user.setAvatarPath(file.getPath());
			user.setAvatar(file.getName());

			userDao.update(user);

			if (StringUtils.isNotBlank(oldPath)) {
				FileUtils.deleteQuietly(new File(oldPath));
			}
			map.put("fileName", file.getName());

			// 更新缓存用户信息
			UserInfo cacheUserInfo = AuthUserHolder.getUserInfo();
			cacheUserInfo.setAvatar(file.getName());
			AuthUserHolder.setUserInfo(cacheUserInfo);
		} catch (Exception e) {
			LoggerUtil.error(e.getMessage());
			throw new SystemException("图片上传失败");
		}

		return map;
	}

	public void getAvatar(String fileName) {
		if (StringUtils.isBlank(fileName)) {
			return;
		}
		try {
			String path = ConfigUtil.getAppConfig().getFile().getPath() + FileConstants.avatar + "/" + fileName;
			FileUtils.download(path);
		} catch (Exception e) {
			LoggerUtil.error(e.getMessage());
		}
	}

}
